﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Tetris.Interfaces;
using Tetris.Utility;

namespace Tetris.Screens
{
    public class ScreenManager: IScreenManager
    {
        private IList<GameScreen> _screens = new List<GameScreen>();
        private IList<GameScreen> _screensToUpdate = new List<GameScreen>();
        private IList<GameScreen> _screensToAdd = new List<GameScreen>();
        private IList<GameScreen> _screensToRemove = new List<GameScreen>();
        private IInputManager _inputManager;
        private Texture2D _blankTexture;
        private bool _isInitialized;
        private IGameManager _gameManager;

        public IList<GameScreen> Screens
        {
            get { return _screens; }
        }

        public ScreenManager( IInputManager inputManager )
        {
            _inputManager = inputManager;
        }

        public void Initialize( IGameManager gameManager )
        {
            _gameManager = gameManager;
            _isInitialized = true;

            _blankTexture = gameManager.Game.Content.Load<Texture2D>( Constants.Content.Graphics.BLANK );

            foreach( GameScreen screen in _screens )
            {
                screen.Initialize( gameManager );
            }
        }

        public void Update( IGameManager gameManager )
        {
            SynchronizeScreens();

            _inputManager.UpdateKeyboardState();
            _screensToUpdate.Clear();

            foreach( GameScreen screen in _screens )
            {
                _screensToUpdate.Add( screen );
            }

            bool otherScreenHasFocus = !gameManager.Game.IsActive;
            bool coveredByOtherScreen = false;

            while( _screensToUpdate.Count > 0 )
            {
                GameScreen screen = _screensToUpdate[_screensToUpdate.Count - 1];

                _screensToUpdate.RemoveAt( _screensToUpdate.Count - 1 );
                screen.Update( gameManager.GameTime, otherScreenHasFocus, coveredByOtherScreen );

                if( screen.ScreenState == ScreenState.TransitioningIn ||
                    screen.ScreenState == ScreenState.Active )
                {
                    if( !otherScreenHasFocus )
                    {
                        screen.HandleInput( _inputManager );

                        otherScreenHasFocus = true;
                    }

                    // More than one screen => inform subsequent screens that they are covered
                    //coveredByOtherScreen = true;

                    // If this is an active non-popup, inform any subsequent
                    // screens that they are covered by it.
                    if (!screen.IsPopup)
                        coveredByOtherScreen = true;
                }
            }
        }

        private void SynchronizeScreens()
        {
            foreach (GameScreen screen in _screensToRemove)
            {
                _screens.Remove(screen);
            }
            _screensToRemove.Clear();
            foreach (GameScreen screen in _screensToAdd)
            {
                _screens.Add(screen);
            }
            _screensToAdd.Clear();
        }

        public void Draw( SpriteBatch spriteBatch, IGameManager gameManager, GameTime gameTime )
        {
            foreach( GameScreen screen in _screens )
            {
                if( screen.ScreenState == ScreenState.Hidden )
                {
                    continue;
                }

                screen.Draw( spriteBatch, gameManager, gameTime );
            }
        }

        public void AddNotification(string text)
        {
            AddScreen(_gameManager, new NotificationScreen(text, 3), null);
        }

        public void AddScreen( IGameManager gameManager, GameScreen screen, PlayerIndex? controllingPlayer )
        {
            screen.ControllingPlayer = controllingPlayer;
            screen.ScreenManager = this;
            screen.IsExiting = false;
            screen.Initialize( gameManager );

            _screensToAdd.Add(screen);
        }

        public void RemoveScreen( GameScreen screen )
        {
            _screensToRemove.Add(screen);
        }

        public void FadeBackBufferToBlack( float alpha, SpriteBatch spriteBatch, IGameManager gameManager )
        {
            Viewport viewport = gameManager.Game.GraphicsDevice.Viewport;

            spriteBatch.Begin();
            spriteBatch.Draw( _blankTexture,
                              new Rectangle( 0, 0, viewport.Width, viewport.Height ),
                              Color.Black * alpha );
            spriteBatch.End();
        }
    }
}
